package com.xframework.security.controller;

import java.util.*;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.xframework.Base;
import com.xframework.exception.BusinessException;
import io.jsonwebtoken.Claims;
import com.xframework.security.util.*;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import com.xframework.security.api.SecurityRpcService;
import com.xframework.security.model.*;

@RestController
public class SecurityController {

    @DubboReference
    private SecurityRpcService securityRpcService;

    public SecurityController() {
        System.out.println("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx SecurityControlle xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    }

    @PostConstruct
    public void init() {

    }

    @RequestMapping(value = "/login")
    public SecurityAccount login(@RequestBody SecurityAccount securityAccount, HttpServletRequest request, HttpServletResponse response) {
        String accountName = securityAccount.getAccountName();
        String accountRandom = securityAccount.getAccountRandom();
        String accountPassword = securityAccount.getAccountPassword();
        if (!Base.isString(accountName)) {
            throw new BusinessException(Constant.securityAccountErrorMessage);
        }
        String applicationId = securityAccount.getApplicationId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        String securityLoginUrl = securityAccount.getSecurityLoginUrl();
        securityLoginUrl = Base.isString(securityLoginUrl) ? securityLoginUrl : Constant.securityLoginUrl;
        String securityLogoutUrl = securityAccount.getSecurityLogoutUrl();
        securityLogoutUrl = Base.isString(securityLogoutUrl) ? securityLogoutUrl : Constant.securityLogoutUrl;
        String securityExceptionUrl = securityAccount.getSecurityExceptionUrl();
        securityExceptionUrl = Base.isString(securityExceptionUrl) ? securityExceptionUrl : Constant.securityExceptionUrl;

        Account account = new Account();
        if (Base.isString(accountRandom)) {
            boolean flag = securityRpcService.verifyRandom(accountName, accountRandom);
            if (!flag) {
                throw new BusinessException(Constant.securityAccountErrorMessage);
            }
        } else if (Base.isString(accountPassword)) {
            account.setAccountPassword(accountPassword);
        } else {
            throw new BusinessException(Constant.securityAccountErrorMessage);
        }
        account.setAccountName(accountName);
        account.setAccountState(1);
        securityAccount = securityRpcService.selectAccount(account, applicationId, this.getClientIp(request));

        if (securityAccount != null) {
            securityAccount.setAccountPassword(accountPassword);
            securityAccount.setSecurityLoginUrl(securityLoginUrl);
            securityAccount.setSecurityLogoutUrl(securityLogoutUrl);
            securityAccount.setSecurityExceptionUrl(securityExceptionUrl);
            String securityToken = JWTUtil.createJWT(securityAccount);
            response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
            response.setHeader(Constant.ACCESS_CONTROL_EXPOSE_HEADERS, Constant.Authorization);
            response.setHeader(Constant.Authorization, securityToken);
        } else {
            throw new BusinessException(Constant.securityAccountErrorMessage);
        }
        return securityAccount;
    }

    @RequestMapping(value = "/authentication")
    public boolean authentication(HttpServletRequest request) {
        boolean flag = Boolean.FALSE;
        String securityToken = request.getHeader(Constant.Authorization);
        if (securityToken != null) {
            Claims payload = JWTUtil.parserJWT(securityToken);
            if (payload != null) {
                flag = Boolean.TRUE;
            }
        }
        return flag;
    }

    @RequestMapping(value = "/logout", method = {RequestMethod.POST})
    public ModelAndView logout(HttpServletRequest request,
                               @RequestParam(value = "logoutUrl", required = false) String logoutUrl) {
        request.getSession().removeAttribute(Constant.SECURITY_ACCOUNT);
        request.getSession().invalidate();
        logoutUrl = Base.isString(logoutUrl) ? logoutUrl : Constant.securityLogoutUrl;
        ModelAndView logoutModelAndView = new ModelAndView(logoutUrl);
        return logoutModelAndView;
    }

    @RequestMapping(value = "/selectAccountList")
    public List<Account> selectAccountList(@RequestBody Account account) {
        List<Account> accountList = securityRpcService.selectAccountList(account);
        return accountList;
    }

    @RequestMapping(value = "/selectRoleAccountList")
    public List<Account> selectRoleAccountList(@RequestBody AccountRole accountRole) {
        List<Account> accountList = securityRpcService.selectRoleAccountList(accountRole);
        return accountList;
    }

    @RequestMapping(value = "/selectAccountNum")
    public int selectAccountNum(@RequestBody Account account) {
        int num = securityRpcService.selectAccountNum(account);
        return num;
    }

    @RequestMapping(value = "/insertAccount")
    public Account insertAccount(@RequestBody Account account) {
        account = securityRpcService.insertAccount(account);
        return account;
    }

    @RequestMapping(value = "/updateAccountByPk")
    public Account updateAccount(@RequestBody Account account) {
        securityRpcService.updateAccount(account);
        return account;
    }

    /**
     * 根据非accountId属性修改账户
     *
     * @param account
     * @author wangbeibei 2021/2/26
     */
    @RequestMapping(value = "/updateAccountByAccount")
    public Account uupdateAccountByAccount(@RequestBody Account account) {
//        securityRpcService.updateAccountByAccount(account);
        return account;
    }

    /**
     * 删除账户及其关联角色
     *
     * @param account
     * @return
     * @author wangbeibei 2021/2/26
     */
    @RequestMapping(value = "/deleteAccount")
    public Account deleteAccount(@RequestBody Account account) {
        securityRpcService.deleteAccount(account);
        return account;
    }

    @RequestMapping(value = "/selectRoleList")
    public List<Role> selectRoleList(@RequestBody Role role) {
        //获取系统ID
        String applicationId = role.getApplicationId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        role.setApplicationId(applicationId);
        List<Role> roleList = securityRpcService.selectRoleList(role);
        return roleList;
    }

    /**
     * 查询账户角色列表
     *
     * @param accountRole
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/selectAccountRoleList")
    public List<Role> selectAccountRoleList(@RequestBody AccountRole accountRole) {
        //获取系统ID
        String applicationId = accountRole.getAccountId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        accountRole.setAccountId(applicationId);
        List<Role> AccountRoleList = securityRpcService.selectAccountRoleList(accountRole);
        return AccountRoleList;
    }

    /**
     * 查询三方角色列表
     *
     * @param thirdRole
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/selectThirdRoleList")
    public List<Role> selectThirdRoleList(@RequestBody ThirdRole thirdRole) {
        List<Role> thirdRoleList = securityRpcService.selectThirdRoleList(thirdRole);
        return thirdRoleList;
    }

    /**
     * 查询角色数量
     *
     * @param role
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/selectRoleNum")
    public int selectRoleNum(@RequestBody Role role) {
        String applicationId = role.getApplicationId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        role.setApplicationId(applicationId);
        int num = securityRpcService.selectRoleNum(role);
        return num;
    }
    /**
     * 查询三方角色数量
     * @param thirdRole
     * @return
     * @author wangbeibei
     */
   @RequestMapping(value = "/selectThirdRoleNum")
    public int selectThirdRoleNum(@RequestBody ThirdRole thirdRole){
        int num = securityRpcService.selectThirdRoleNum(thirdRole);
        return num;
    }

    /**
     * 添加角色及关联资源
     *
     * @param role
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/insertRole")
    public Role insertRole(@RequestBody Role role) {
        String applicationId = role.getApplicationId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        role.setApplicationId(applicationId);
        role = securityRpcService.insertRole(role);
        return role;
    }

    /**
     * 添加三方角色及关联资源
     *
     * @param thirdRole
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/insertThirdRole")
    public ThirdRole insertThirdRole(@RequestBody ThirdRole thirdRole) {
        Role role = thirdRole.getRole();
        String applicationId = role.getApplicationId();
        applicationId = Base.isString(applicationId) ? applicationId : Constant.securityApplicationId;
        role.setApplicationId(applicationId);
        thirdRole.setRole(role);
        thirdRole = securityRpcService.insertThirdRole(thirdRole);
        return thirdRole;
    }

    /**
     * 根据roleId修改角色及关联资源
     *
     * @param role
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/updateRole")
    public Role updateRole(@RequestBody Role role) {
        securityRpcService.updateRole(role);
        return role;
    }

    /**
     * 删除角色及其关联资源
     *
     * @param role
     * @return
     * @author wangbeibei
     */
    @RequestMapping(value = "/deleteRole")
    public Role deleteAccount(@RequestBody Role role) {
        securityRpcService.deleteRole(role);
        return role;
    }

    /**
     * 根据条件分页查询应用列表接口
     *
     * @param application
     * @return List<Application>
     */
    @RequestMapping(value = "/selectApplicationList")
    public List<Application> selectApplicationList(@RequestBody Application application) {
        List<Application> applicationList = securityRpcService.selectApplicationList(application);
        return applicationList;
    }

    /**
     * 查询应用数量
     *
     * @param application
     * @return
     */
    @RequestMapping(value = "/selectApplicationNum")
    public int selectApplicationNum(@RequestBody Application application) {
        return securityRpcService.selectApplicationNum(application);
    }

    /**
     * 新增应用
     *
     * @param application
     * @return application
     */
    @RequestMapping(value = "/insertApplication")
    public Application insertApplication(@RequestBody Application application) {
        application = securityRpcService.insertApplication(application);
        return application;
    }

    /**
     * 更新应用
     *
     * @param application
     * @return application
     */
    @RequestMapping(value = "/updateApplication")
    public Application updateApplication(@RequestBody Application application) {
        securityRpcService.updateApplication(application);
        return application;
    }

    /**
     * 删除应用
     *
     * @param application
     * @return application
     */
    @RequestMapping(value = "/deleteApplication")
    public Application deleteApplication(@RequestBody Application application) {
        securityRpcService.deleteApplication(application);
        return application;
    }

    /**
     * 根据条件分页查询资源列表
     *
     * @param resource
     * @return List<Resource>
     */
    @RequestMapping(value = "/selectResourceList")
    public List<Resource> selectResourceList(@RequestBody Resource resource) {
        List<Resource> resourceList = securityRpcService.selectResourceList(resource);
        return resourceList;
    }

    /**
     * 根据条件分页查询角色下的资源列表
     *
     * @param roleResource
     * @return List<String>
     */
    @RequestMapping(value = "/selectRoleResourceList")
    public List<Resource> selectRoleResourceList(@RequestBody RoleResource roleResource) {
        List<Resource> roleResourceList = securityRpcService.selectRoleResourceList(roleResource);
        return roleResourceList;
    }

    /**
     * 添加资源
     *
     * @param resource
     * @return resource
     */
    @RequestMapping(value = "/insertResource")
    public Resource insertResource(@RequestBody Resource resource) {
        resource = securityRpcService.insertResource(resource);
        return resource;
    }

    /**
     * 修改资源
     *
     * @param resource
     * @return resource
     */
    @RequestMapping(value = "/updateResource")
    public int updateResource(@RequestBody Resource resource) {
        return securityRpcService.updateResource(resource);
    }

    /**
     * 删除资源
     *
     * @param resource
     * @return resource
     */
    @RequestMapping(value = "/deleteResource")
    public Resource deleteResource(@RequestBody Resource resource) {
        securityRpcService.deleteResource(resource);
        return resource;
    }

    /**
     * description : 获取验证码
     *
     * @param map map （mobile：电话号码、length：验证码长度、expireSencods：过期时间）
     * @return 验证码
     * @author wanzhicheng 2021/2/26
     */
    @PostMapping(value = "/genRandom")
    public String genRandom(@RequestBody Map<String, Object> map) {
        return securityRpcService.genRandom((String) map.get("mobile"), (Integer) map.get("length"), (Integer) map.get("expireSencods"));
    }

    /**
     * description : 校验验证码
     *
     * @param map map（mobile：电话号码、random：验证码）
     * @return true、false
     * @author wanzhicheng 2021/2/26
     */
    @PostMapping("/verifyRandom")
    public boolean verifyRandom(@RequestBody Map<String, String> map) {
        return securityRpcService.verifyRandom(map.get("mobile"), map.get("random"));
    }

    private String getClientIp(final HttpServletRequest request) {
        String remoteAddr = request.getHeader(Constant.X_FORWARDED_FOR);
        // 如果通过多级反向代理，X-Forwarded-For的值不止一个，而是一串用逗号分隔的IP值，此时取X-Forwarded-For中第一个非unknown的有效IP字符串
        if (isEffective(remoteAddr) && (remoteAddr.indexOf(Base.COMMA) > -1)) {
            String[] array = remoteAddr.split(Base.COMMA);
            for (String element : array) {
                if (isEffective(element)) {
                    remoteAddr = element;
                    break;
                }
            }
        }
        if (!isEffective(remoteAddr)) {
            remoteAddr = request.getHeader(Constant.X_REAL_IP);
        }
        if (!isEffective(remoteAddr)) {
            remoteAddr = request.getRemoteAddr();
        }
        return remoteAddr;
    }

    private boolean isEffective(final String remoteAddr) {
        boolean isEffective = false;
        if ((null != remoteAddr) && (!Base.BLANK.equals(remoteAddr.trim())) && (!"unknown".equalsIgnoreCase(remoteAddr.trim()))) {
            isEffective = true;
        }
        return isEffective;
    }

}
